package utils

import (
	"archive/tar"
	"compress/gzip"
	errors2 "github.com/pkg/errors"
	"io"
	"io/fs"
	"os"
	"path/filepath"
	"sync"
)

func Extract(f fs.File, dest string) error {
	var wg sync.WaitGroup
	g, err := gzip.NewReader(f)
	if err != nil {
		return errors2.WithMessage(err, "Extract: new gzip Reader failed")
	}
	defer func() {
		err := g.Close()
		if err != nil {
			panic(err)
		}
	}()
	reader := tar.NewReader(g)
	for {
		header, err := reader.Next()
		if err != nil {
			if err == io.EOF {
				break
			} else {
				return errors2.WithMessage(err, "Extract: Reader failed")
			}
		}
		wg.Add(1)
		go create(dest, reader, header, &wg)
		wg.Wait()
	}
	return nil
}

func create(dest string, reader *tar.Reader, header *tar.Header, wg *sync.WaitGroup) {
	defer wg.Done()
	path := filepath.Join(dest, header.Name)
	var err error
	if header.FileInfo().IsDir() {
		err = CreateDir(path)
	} else {
		err = createFile(path, reader)
	}
	if err != nil {
		panic(err)
	}
}

func CreateDir(path string) error {
	err := os.MkdirAll(path, os.ModePerm)
	if err != nil {
		return errors2.WithMessage(err, "createDir failed")
	}
	return nil
}

func createFile(path string, t *tar.Reader) error {
	file, err := os.Create(path)
	if err != nil {
		return errors2.WithMessage(err, "createFile failed")
	}
	_, err = io.Copy(file, t)
	if err != nil {
		return errors2.WithMessage(err, "CopyFile failed")
	}
	return nil
}
